<template>
  <div v-if="showLayerGroup" class="container" :style="Object.assign({ height: `${menuContainerHeight}px` }, singleComponentSizeScale, singleComponentPaddingConfigStyle)">
    <div
      v-for="item,index of rebuildLayerGroup"
      class="menu-container"
      :key="index"
      :class="[currentMenuIndex === index ? 'menu-container-hovered' : '', selectedLayerIds.includes(item.groupId) || hasIncludedLayerSelected(item.layers) ? 'menu-container-selected' : '']"
      :style="{ cursor: item.layers.length ? 'default' : 'pointer' }"
      @mouseenter="subMenuOpen(index)"
      @mouseleave="subMenuClose"
      @click="layerGroupClick(item)"
    >
      <div class="name">
        <img v-if="!selectedLayerIds.includes(item.groupId) && !hasIncludedLayerSelected(item.layers)" :src="getLayerIcon(item.groupIcon)" />
        <img v-else :src="getLayerIcon(item.groupSelectedIcon)" />
        <p>{{ item.groupName }}</p>
      </div>
      <div v-if="item.layers.length" class="more-icon"></div>
      <div v-if="currentMenuIndex === index && currentSubMenu.length" class="sub-menu-container">
        <div class="indicating-container">
          <div class="indicating"></div>
        </div>
        <div class="content" :style="{ bottom: `${subMenuContainerBottomDistance}px` }">
          <div v-for="subItem of currentSubMenu" class="item-container" :key="subItem.id" :class="selectedLayerIds.includes(subItem.id) ? 'item-container-selected' : ''" @click="layerClick(subItem)">
            <img :src="getLayerIcon(subItem.layerIcon)" />
            <p>{{ subItem.layerName }}</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { componentSizeScale } from '@utils'
import defaultIcon from '@assets/map/map-icon/map-icon-default.png'

export default {
  name: 'POILayerManagement',
  props: {
    layerGroup: {
      type: Array,
      required: true,
      default: () => []
    },
    // 是否展示图层组，默认为true
    showLayerGroup: {
      type: Boolean,
      required: false,
      default: true
    },
    // 展示图层组模式(即控制展示显示状态或隐藏状态的图层组)，默认为1(显示状态)，可用值为：0-控制展示隐藏状态的图层组参数值，1-控制展示显示状态的参数值
    showLayerGroupMode: {
      type: Number,
      required: false,
      default: 1
    },
    // 选中图层模式，默认为1，可用值为：0-多选模式，1-单选模式
    checkLayerMode: {
      type: Number,
      required: false,
      default: 1
    },
    // 初始化时展示图层的模式，默认为1，可用值为：-1-全显示模式，0-不显示模式，1-首图层模式，2-正序排列前2图层模式，...，n-正序排列前n图层模式
    initShowLayerMode: {
      type: Number,
      required: false,
      default: 1
    }
  },
  data() {
    return {
      originalDesignSize: {
        width: 7680,
        height: 2160
      }, // 组件设计尺寸基准数值(同大屏原始设计尺寸保持一致)
      simpleMenuHeightInCss: 68, // css中设置的单个图层组菜单高度值，当前为68
      spacingInMenus: 20, // 图层组菜单间距常量值，默认为20
      menuLimitedNumber: 6, // 图层组展示菜单数量限制数量，默认为6
      currentMenuIndex: null, // 当前鼠标移入的图层(组)菜单对应索引参数
      currentSubMenu: [], // 当前打开的图层子菜单图层数据对象参数
      selectedLayerIds: [], // 选中的图层id集合数组参数
      selectedLayerInfo: [], // 选中的图层数据信息数组参数
      initShowLayerNumber: this.initShowLayerMode // 初始化时展示图层的数量
    }
  },
  computed: {
    // 动态计算组件尺寸缩放比例
    singleComponentSizeScale: function() {
      const scale = componentSizeScale(this.originalDesignSize.width, this.originalDesignSize.height)
      return {
        '--scaleX': scale.scaleX,
        '--scaleY': scale.scaleY,
        '--scaleRelative': scale.scaleRelative,
        '--scaleFontRelative': scale.scaleFontRelative
      }
    },
    // 动态计算组件四周空隙留白(padding)样式
    singleComponentPaddingConfigStyle: function() {
      return {
        '--paddingTop': _const.mapConfigInfo.effectConfig.componentPaddingConfig.top,
        '--paddingRight': _const.mapConfigInfo.effectConfig.componentPaddingConfig.right,
        '--paddingBottom': _const.mapConfigInfo.effectConfig.componentPaddingConfig.bottom,
        '--paddingLeft': _const.mapConfigInfo.effectConfig.componentPaddingConfig.left
      }
    },
    // 动态计算图层组菜单容器高度值
    menuContainerHeight: function() {
      const simpleMenuHeight = this.simpleMenuHeightInCss * this.singleComponentSizeScale['--scaleY']
      const currentSpacingInMenus = this.spacingInMenus * this.singleComponentSizeScale['--scaleY']
      let calculatedHeight = 0
      const displayedLayerGroup = this.layerGroup.filter(item => {
        if (this.showLayerGroupMode) return item.isShow
        else return !item.isShow
      })
      if (displayedLayerGroup.length) {
        const numberLimit = displayedLayerGroup.length > this.menuLimitedNumber ? this.menuLimitedNumber : displayedLayerGroup.length // 纵向排列最大限制
        calculatedHeight = simpleMenuHeight * numberLimit + currentSpacingInMenus * (numberLimit - 1) // 计算高度值(计算公式：css中设置的单个图层组菜单高度*纵向排列最大限制+图层组菜单间距*(纵向排列最大限制-1))
      }
      return calculatedHeight
    },
    // 重新构建图层组数据
    rebuildLayerGroup: function() {
      const newLayerGroup = []
      for (const item of this.layerGroup) {
        let currentLayerGroup = {}
        if ((this.showLayerGroupMode && !item.isShow) || (!this.showLayerGroupMode && item.isShow) || !item.layerInfoList.length) continue // 按照传参，过滤掉(隐藏/显示)以及空图层组
        if (item.layerInfoList.length === 1) {
          currentLayerGroup = {
            groupId: item.layerInfoList[0].id,
            groupName: item.groupName,
            groupIcon: item.groupIcon,
            groupSelectedIcon: item.groupSelectedIcon,
            layers: []
          }
        } else if (item.layerInfoList.length > 1) {
          currentLayerGroup = {
            groupId: null,
            groupName: item.groupName,
            groupIcon: item.groupIcon,
            groupSelectedIcon: item.groupSelectedIcon,
            layers: item.layerInfoList
          }
        }
        newLayerGroup.push(currentLayerGroup)
      }
      return newLayerGroup
    },
    // 构建隐藏图层组数据
    buildHiddenLayerGroup: function() {
      let newLayerGroup = []
      for (const item of this.layerGroup) {
        if (item.isShow || !item.layerInfoList.length) continue // 过滤掉显示或空图层组
        newLayerGroup = [...newLayerGroup, ...item.layerInfoList]
      }
      return newLayerGroup
    },
    // 动态计算图层子菜单容器到图层组菜单底部的距离
    subMenuContainerBottomDistance: function() {
      const simpleMenuHeight = this.simpleMenuHeightInCss * this.singleComponentSizeScale['--scaleY']
      const currentSpacingInMenus = this.spacingInMenus * this.singleComponentSizeScale['--scaleY']
      const subMenuContainerPaddingHeightInCss = 20 * this.singleComponentSizeScale['--scaleY'] // css中设置的图层子菜单容器padding高度值(当前上下为10*缩放比例(--scaleY)]px，和为20*缩放比例(--scaleY)]px)
      const simpleSubMenuHeightInCss = 60 * this.singleComponentSizeScale['--scaleY'] // css中设置的图层子菜单单行高度值，当前为[60*缩放比例(--scaleY)]px
      const subMenuContainerMaxHeightInCss = 620 * this.singleComponentSizeScale['--scaleY'] // css中设置的图层子菜单容器最大高度值，当前为[620*缩放比例(--scaleY)]px
      const subMenuContainerCalcHeight = subMenuContainerPaddingHeightInCss + this.currentSubMenu.length * simpleSubMenuHeightInCss // 计算图层子菜单理论高度(计算公式：图层子菜单容器padding高度+图层子菜单数量*图层子菜单单行行高)
      const subMenuContainerHeight = subMenuContainerMaxHeightInCss > subMenuContainerCalcHeight ? subMenuContainerCalcHeight : subMenuContainerMaxHeightInCss // 获取图层子菜单真实高度
      const currentMenuBottomDistanceOfMiddle = this.menuContainerHeight - (simpleMenuHeight / 2 + (simpleMenuHeight + currentSpacingInMenus) * this.currentMenuIndex) // 计算当前图层菜单中线距底高度(计算公式：图层组菜单容器高度-(css中设置的单个图层组菜单高度/2+(css中设置的单个图层组菜单高度+图层组菜单间距)*当前图层菜单对应索引值))
      let distance = 0 // 默认距底值设置为0
      if (currentMenuBottomDistanceOfMiddle > subMenuContainerHeight / 2) distance = currentMenuBottomDistanceOfMiddle - subMenuContainerHeight / 2 // 当前图层组菜单中线距底高度大于图层子菜单1/2高度(即图层子菜单可居中展开显示)，设置图层子菜单距底高度值为两者差值(计算公式：当前图层菜单中线距底高度-图层子菜单高度/2)
      return distance
    }
  },
  watch: {
    rebuildLayerGroup(value) {
      // 监听重新构建图层组数据参数，用于实现数据初始化时，触发选中图层
      if (!value.length) return
      if (this.initShowLayerMode === 0) return // 初始化展示模式为不显示模式，返回
      const layerGroups = value
      // 根据传参设置触发选中正序排列的相应数量(前n)的图层
      if (this.checkLayerMode) this.initShowLayerNumber = 1 // 单选模式时，重新设置全局参数初始化时展示图层的数量参数initShowLayerNumber为1(即只选中首图层)
      for (const item of layerGroups) {
        if (this.initShowLayerNumber === -1) {
          // 初始化展示模式为全显示模式，遍历图层组触发选中图层
          if (item.layers.length) {
            // 子图层遍历
            for (const subItem of item.layers) {
              this.layerClick(subItem) // 触发选中图层
            }
          } else {
            this.layerGroupClick(item) // 触发选中图层组
          }
        } else {
          // 初始化展示模式为指定数量显示模式，根据指定数量，触发选中图层，使用initShowLayerNumber参数的值为0时作为遍历终止标识
          if (this.initShowLayerNumber === 0) break // 判断标识，归0时，结束图层组遍历
          if (item.layers.length) {
            // 子图层遍历
            for (const subItem of item.layers) {
              if (this.initShowLayerNumber === 0) break // 判断标识，归0时，结束子图层遍历
              this.layerClick(subItem) // 触发选中图层
              this.initShowLayerNumber-- // 遍历标识自减1
            }
          } else {
            this.layerGroupClick(item) // 触发选中图层组
            this.initShowLayerNumber-- // 遍历标识自减1
          }
        }
      }
    },
    buildHiddenLayerGroup(value) {
      this.$emit('hiddenLayerGroup', value)
    }
  },
  mounted() {
    // 监听由外部触发的POI图层选中状态变更触发器事件，进行数据驱动更新
    this.$eventBus.$on('externalTriggerOfPOILayerSelectedStatusChange', ({ layerId, action }) => {
      let isSelectLayer = true
      if (action === 1) isSelectLayer = false
      this.passiveUpdateSelectedLayerData(layerId, isSelectLayer) // 被动式更新选中的图层数据
    })
  },
  beforeDestroy() {
    this.$eventBus.$off('externalTriggerOfPOILayerSelectedStatusChange') // 事件监听卸载
  },
  methods: {
    // 鼠标移入图层组菜单事件响应(图层子菜单打开逻辑)
    subMenuOpen(index) {
      this.currentMenuIndex = index
      this.currentSubMenu = this.rebuildLayerGroup[index].layers
    },
    // 鼠标移出图层组菜单事件响应(图层子菜单关闭逻辑)
    subMenuClose() {
      this.currentMenuIndex = null
      this.currentSubMenu = []
    },
    // 获取图层(组)图标(完整路径)
    getLayerIcon(origin) {
      let generalIcon = defaultIcon
      if (origin !== null) {
        generalIcon = `${window._CONFIG['domianURL']}/${origin}`
        if (origin.substring(0, 4) === 'http') generalIcon = `${origin}`
      }
      return generalIcon
    },
    // 图层组包含图层是否存在选中状态判断方法
    hasIncludedLayerSelected(layers) {
      if (layers.some(item => this.selectedLayerIds.includes(item.id))) {
        return true
      } else {
        return false
      }
    },
    // 图层组菜单点击响应
    layerGroupClick(data) {
      if (!data.layers.length) {
        // 当前仅处理图层组即图层情况
        const rebuildLayerInfo = {
          id: data.groupId,
          layerName: data.groupName
        }
        this.layerClick(rebuildLayerInfo)
      }
    },
    // 图层子菜单点击响应
    layerClick(data) {
      let actionFlag = ''
      let fullLayerName = data.layerName
      // 查询图层对应图层组名称(若存在),并拼接生成全新图层名称
      for (const item of this.rebuildLayerGroup) {
        if (!item.layers.length) continue
        let endFlag = false
        for (const subItem of item.layers) {
          if (subItem.id === data.id) {
            fullLayerName = `${item.groupName}-${fullLayerName}`
            endFlag = true
            break
          }
        }
        if (endFlag) break
      }
      const clickedLayerInfo = {
        name: fullLayerName,
        id: data.id
      }
      if (this.selectedLayerIds.includes(data.id)) {
        actionFlag = 'remove'
        this.selectedLayerIds.splice(this.selectedLayerIds.findIndex(item => item === data.id), 1)
        this.selectedLayerInfo.splice(this.selectedLayerInfo.findIndex(item => item.id === data.id), 1)
      } else {
        actionFlag = 'add'
        if (this.checkLayerMode) this.selectedLayerParamsUpdateWithRadioCheckLayerModeWhenShowStatusLayerSelect() // 单选模式下，选中图层相关参数按需更新
        this.selectedLayerIds.push(data.id)
        this.selectedLayerInfo.push(clickedLayerInfo)
      }
      const param = {
        action: actionFlag,
        layerInfo: [clickedLayerInfo],
        selectedLayerIds: this.selectedLayerIds
      }
      if (this.showLayerGroupMode) this.$emit('change', param)
      else this.$emit('hideChange', param)
    },
    // 被动式更新选中的图层数据
    passiveUpdateSelectedLayerData(layerId, isSelectLayer = true) {
      let fullLayerName = ''
      // 查询图层对应图层(组)，拼接生成图层名称
      for (const item of this.rebuildLayerGroup) {
        if (!item.layers.length) {
          if (item.groupId === layerId) {
            fullLayerName = item.groupName // 单一图层(无子图层)，获取其图层名称
            break
          }
          continue
        }
        let endFlag = false
        for (const subItem of item.layers) {
          if (subItem.id === layerId) {
            fullLayerName = `${item.groupName}-${subItem.layerName}` // 子图层，拼接生成图层名称
            endFlag = true
            break
          }
        }
        if (endFlag) break
      }
      // 生成更新选中的图层信息
      const updateSelectedLayerInfo = {
        name: fullLayerName,
        id: layerId
      }
      let actionFlag = ''
      // 根据传入参数isSelectLayer确认是数据被动添加或是数据移除
      if (isSelectLayer) {
        if (fullLayerName !== '') {
          // 当添加的是展示的图层(由于fullLayerName取值从展示图层中，可根据fullLayerName取值判断)时，进行相关参数赋值更新
          actionFlag = 'passiveUpdate' // 添加动作标识符参数赋值为passiveUpdate(被动添加更新)，用于外部数据交互联动
          if (this.checkLayerMode) {
            // 单选模式时，根据展示图层组模式，进行选中图层相关参数处理
            if (this.showLayerGroupMode) this.selectedLayerParamsUpdateWithRadioCheckLayerModeWhenShowStatusLayerSelect() // 展示显示状态图层时，选中图层相关参数按需更新
            else {
              // 展示隐藏状态图层时，选中图层相关参数重置为空(此处暂不考虑显式展示模式图层)
              this.selectedLayerIds = []
              this.selectedLayerInfo = []
            }
          }
        }
        this.selectedLayerIds.push(layerId)
        this.selectedLayerInfo.push(updateSelectedLayerInfo)
      } else {
        actionFlag = 'remove'
        const indexOfLayerIdInSelectedLayerIds = this.selectedLayerIds.indexOf(layerId)
        if (indexOfLayerIdInSelectedLayerIds !== -1) {
          this.selectedLayerIds.splice(indexOfLayerIdInSelectedLayerIds, 1)
          this.selectedLayerInfo.splice(indexOfLayerIdInSelectedLayerIds, 1)
        }
      }
      const param = {
        action: actionFlag,
        layerInfo: [updateSelectedLayerInfo],
        selectedLayerIds: this.selectedLayerIds
      }
      if (this.showLayerGroupMode) this.$emit('change', param)
      else this.$emit('hideChange', param)
    },
    // 单选模式下选中显式展示模式图层操作时选中图层相关参数更新
    selectedLayerParamsUpdateWithRadioCheckLayerModeWhenShowStatusLayerSelect() {
      // 获取当前选中图层中所有隐式展示模式的图层
      const hiddenLayerIdsInSelectedLayerIds = this.selectedLayerIds.filter(item => {
        let hasHiddenLayerFlag = false
        for (const layerInfo of this.buildHiddenLayerGroup) {
          if (item === layerInfo.id) {
            hasHiddenLayerFlag = true
            break
          }
        }
        return hasHiddenLayerFlag
      })
      // 根据当前选中图层中是否存在隐式展示模式的图层，进行选中图层相关参数更新
      if (hiddenLayerIdsInSelectedLayerIds.length) {
        // 若当前选中图层中存在隐式展示模式的图层，则进行选中图层相关参数更新(保留选中图层相关参数中的隐式展示模式图层，剔除选中图层相关参数中的显式展示模式图层)
        this.selectedLayerIds = [...hiddenLayerIdsInSelectedLayerIds] // 深拷贝更新selectedLayerIds
        // 深拷贝更新selectedLayerInfo
        const selectedHiddenLayerInfo = this.selectedLayerInfo.filter(item => {
          return this.selectedLayerIds.includes(item.id)
        })
        this.selectedLayerInfo = [...selectedHiddenLayerInfo]
      } else {
        // 若当前选中图层中不存在隐式展示模式的图层，则进行选中图层相关参数置空(全量剔除选中图层相关参数中的显式展示模式图层)
        this.selectedLayerIds = []
        this.selectedLayerInfo = []
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.container {
  position: absolute;
  left: calc(var(--paddingLeft) + 80px * var(--scaleX));
  bottom: var(--paddingBottom);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  z-index: 3;
  .menu-container {
    width: calc(340px * var(--scaleX));
    height: calc(68px * var(--scaleY));
    background-size: 100% 100%;
    background-repeat: no-repeat;
    background-image: url("./images/menu-background.png");
    .name {
      line-height: calc(68px * var(--scaleY));
      font-size: calc(36px * var(--scaleFontRelative));
      color: #f1f2f7;
      display: flex;
      align-items: center;
      & > img {
        width: calc(35px * var(--scaleX));
        height: calc(35px * var(--scaleY));
        margin-right: calc(-10px * var(--scaleX));
        margin-left: calc(20px * var(--scaleX));
      }
      & > p {
        max-width: calc(240px * var(--scaleX));
        margin-left: calc(20px * var(--scaleX));
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow: hidden;
      }
    }
    .more-icon {
      width: calc(28px * var(--scaleX));
      height: calc(20px * var(--scaleY));
      position: relative;
      left: calc(277px * var(--scaleX));
      top: calc(-44px * var(--scaleY));
      margin: 0 calc(20px * var(--scaleX));
      background-size: 100% 100%;
      background-repeat: no-repeat;
      background-image: url("./images/sub-menu-exist-icon.png");
    }
  }
  .menu-container-selected {
    background-image: url("./images/menu-selected-background.png") !important;
    .name {
      font-weight: bold;
      background: linear-gradient(0deg, #f7ab00 0%, #ffffff 100%);
      background-clip: text;
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
    }
    .more-icon {
      background-size: 100% 100%;
      background-repeat: no-repeat;
      background-image: url("./images/sub-menu-exist-selected-icon.png");
    }
  }
  .menu-container-hovered {
    background-image: url("./images/menu-hovered-background.png");
    .name {
      font-weight: bold;
    }
    .sub-menu-container {
      .indicating-container {
        width: calc(21px * var(--scaleX));
        height: calc(68px * var(--scaleY));
        position: relative;
        bottom: calc(90px * var(--scaleY));
        left: calc(340px * var(--scaleX));
        display: flex;
        align-items: center;
        .indicating {
          width: 100%;
          height: calc(27px * var(--scaleY));
          background-size: 100% 100%;
          background-repeat: no-repeat;
          background-image: url("./images/sub-menu-indicating-arrow.png");
        }
      }
      .content {
        min-width: calc(200px * var(--scaleX));
        max-height: calc(620px * var(--scaleY));
        position: absolute;
        left: calc(361px * var(--scaleX));
        padding: calc(10px * var(--scaleY)) calc(20px * var(--scaleX));
        border: #fabe00 calc(3px * var(--scaleRelative)) solid;
        background: #006bb9;
        box-shadow: 0 0 calc(30px * var(--scaleRelative)) calc(5px * var(--scaleRelative)) #39a3fd33 inset;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        overflow-y: auto;
        white-space: nowrap;
        .item-container {
          line-height: calc(60px * var(--scaleY));
          font-size: calc(54px * var(--scaleFontRelative));
          color: #f1f2f7;
          display: flex;
          align-items: center;
          cursor: pointer;
          &:hover {
            font-weight: bold;
            transform: scale(1.05);
          }
          & > img {
            width: calc(40px * var(--scaleX));
            height: calc(40px * var(--scaleY));
            margin-right: calc(10px * var(--scaleX));
          }
        }
        .item-container-selected {
          font-weight: bold;
          color: #fabe00;
        }
      }
    }
  }
  ::v-deep ::-webkit-scrollbar {
    width: calc(10px * var(--scaleX));
    height: calc(10px * var(--scaleY));
    background-color: #06376f;
  }
  ::v-deep ::-webkit-scrollbar-track {
    border-radius: calc(10px * var(--scaleRelative));
    background-color: #3d6bff;
  }
  ::v-deep ::-webkit-scrollbar-thumb {
    border-radius: calc(4px * var(--scaleRelative));
    -webkit-box-shadow: inset 0 0 6px #0000004d;
    background-color: #25deff;
  }
}
</style>
